#include "bitmap.h"

#include <common.h>
#include <log.h>
#include <stdio.h>

////////////////////////////////////////////////////////////////////////////////

struct BitmapFileHeader
{
  uint16 type;
  uint32 size;
  uint16 reserved1;
  uint16 reserved2;
  uint32 offset;
};

struct BitmapInfoHeader
{
  uint32 size;
  int32 width;
  int32 height;
  uint16 planes;
  uint16 bit_count;
  uint32 compression;
  uint32 size_image;
  int32 x_pixels_per_meter;
  int32 y_pixels_per_meter;
  uint32 clr_used;
  uint32 clr_important;
};

////////////////////////////////////////////////////////////////////////////////

const char* Bitmap_getErrorString(BitmapError error)
{
  const char* str = "unknown";
  
  switch (error)
  {
    case BITMAP_ERROR_OK: str = "ok"; break;
    case BITMAP_ERROR_FAIL_OPEN_FILE: str = "failed to open file"; break;
    case BITMAP_ERROR_WRONG_FILE_TYPE: str = "wrong file type"; break;
    case BITMAP_ERROR_WRONG_DATA_TYPE: str = "wrong data type"; break;
    
    default:
      break;
  }
  
  return str;
}

BitmapError Bitmap_load(Image* bitmap, const char* filename)
{
  BitmapFileHeader file_header;
  BitmapInfoHeader info_header;
  FILE* file = fopen(filename, "rb");
  uint8* data;
  
  if (!file)
  {
    return BITMAP_ERROR_FAIL_OPEN_FILE;
  }
  
  fread(&file_header.type, 2, 1, file);
  fread(&file_header.size, 4, 1, file);
  fread(&file_header.reserved1, 2, 1, file);
  fread(&file_header.reserved2, 2, 1, file);
  fread(&file_header.offset, 4, 1, file);
  
  if (file_header.type != 19778)
  {
    return BITMAP_ERROR_WRONG_FILE_TYPE;
  }
  
  fread(&info_header, sizeof(info_header), 1, file);
  
  if (info_header.planes != 1 || info_header.bit_count != 24 ||
    info_header.compression != 0)
  {
    return BITMAP_ERROR_WRONG_DATA_TYPE;
  }
  
  unsigned data_size = file_header.size - file_header.offset;
  unsigned line_size = 3 * info_header.width;
  unsigned padding = (4 * (line_size / 4)) - line_size;
  
  data = new uint8[data_size];
  
  fseek(file, file_header.offset, SEEK_SET);
  fread(data, 1, data_size, file);
  fclose(file);
  
  bitmap->width = info_header.width;
  bitmap->height = info_header.height;
  bitmap->colour = new Colour[info_header.width * info_header.height];
  
  uint8* pix = data;
  Colour* colour = bitmap->colour;
  
  for (int y = info_header.height - 1; y >= 0; y--)
  {
    for (int x = 0; x < info_header.width; x++)
    {
      colour[info_header.width * y + x] = Colour(pix[2], pix[1], pix[0], 0xFF);
      
      pix += 3;
    }
    
    pix += padding;
  }
  
  delete[] data;
  
  return BITMAP_ERROR_OK;
}
